package operations;

import java.util.Map;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import util.Randomness;

import model.CUT;
import model.ConstantDeclared;
import model.StatementKind;
import model.TestClusterBuilder;

public class AssignConstant extends Operation{
	private final Class<?> declaringClass;
	private final Class<?> type;
	private  String ref;
	private final Field value;
	public AssignConstant(Class<?> declaringClass,Class<?> type,String ref, Field value) {
		this.declaringClass=declaringClass;
		this.type=type;
		this.ref = ref;
		this.value = value;
	}
	

	public Class<?> getType() {
		return type;
	}
	public Class<?> getDeclaringClass() {
		return declaringClass;
	}
	public  String  getRefrence(){
		return this.ref;		
	}
	public  void  setRefrence(String ref_){
		 this.ref=ref_;		
	}

	public  Field  getValue(){
		return this.value;		
	}

	public static AssignConstant generate(CUT cut,TestClusterBuilder TestCluster){
//		if(cut.getClazz().equals("java.util.Locale"))
//			System.out.println("AssignConstant.generate: "+cut.getClazz() );

		Map<String, String[]> refFactory = TestCluster.getRefFactory();
		
		ConstantDeclared[]  constants=cut.getConstants();
		List <ConstantDeclared> constantsList=Arrays.asList(constants);
	
		if(constantsList.size()==0) return null;
	
		List<Class<?>> constantType = new ArrayList<Class<?>>(new ArrayList<Class<?>>(constantsList.keySet()));   
		Class<?> classFieldTpe =constantType.get(Randomness.nextRandomInt(constantsList.size())) ;

		
		List<Field> constantsFileds=constantsList.get(classFieldTpe);
		String[] refrences=refFactory.get(classFieldTpe.getName());
		if(refrences==null) return null;
		int randRef=Randomness.nextRandomInt(refrences.length);
		String ref= refrences[randRef];
		Field value=null;
		if( !ValuesGenerator.getBoolean(Operation.SET_TO_NULL)){
			int randField=Randomness.nextRandomInt(constantsFileds.size());
			 value= constantsFileds.get(randField);
			//value=field.getName();
			if (value.getType().equals(classFieldTpe))
				return new AssignConstant(cut.getClazz(),classFieldTpe,ref,value);
			
		}else
		    return new AssignConstant(cut.getClazz(),classFieldTpe,ref,null);
		
		return null;
	
	}
	public static AssignConstant recommendedgenerate(Class<?> clz,StatementKind constr, TestClusterBuilder TestCluster){
		CUT cut=TestCluster.getCluster().get(clz.getName());

		Map<String, String[]> refFactory = TestCluster.getRefFactory();		
		 Map<Class<?>,List<Field>> constantsList=cut.getConstants();
		if(constantsList.size()==0) return null;
	
		List<Class<?>> constantType = new ArrayList<Class<?>>(new ArrayList<Class<?>>(constantsList.keySet()));   
		Class<?> classFieldTpe =constantType.get(Randomness.nextRandomInt(constantsList.size())) ;
		
		List<Field> constantsFileds=constantsList.get(classFieldTpe);
		String[] refrences=refFactory.get(classFieldTpe.getName());
		int randRef=Randomness.nextRandomInt(refrences.length);
		String ref= refrences[randRef];
		Field value=null;
		if( !ValuesGenerator.getBoolean(Operation.SET_TO_NULL)){
			int randField=Randomness.nextRandomInt(constantsFileds.size());
			 value= constantsFileds.get(randField);
			//value=field.getName();
			if (value.getType().equals(classFieldTpe))
				return new AssignConstant(cut.getClazz(),classFieldTpe,ref,value);
			
		}else
		    return new AssignConstant(cut.getClazz(),classFieldTpe,ref,null);
		
		return null;
	
	}
	

	@Override
	public Operation clone() {
		final AssignConstant clone = new AssignConstant(declaringClass,type,ref, value);

		return clone;
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("  "+ref+ " = ");
		if(value == null)  sb.append("null".toString() );
		else	
			sb.append(type.getName()+"." + value.getName());
		
		return sb.toString();

	}


}
